#include "linux/string.h"
#include "linux/rbtree.h"
#include "linux/err.h"
#include "linux/printk.h"
#include "linux/page.h"
#include "linux/sched.h"
#include "linux/mm.h"
#include "linux/common.h"
#include "linux/error.h"
#include "linux/fs.h"
#include "arm/pgalloc.h"
#include "asm/pgtable.h"
#include "uapi/asm-generic/mman-common.h"

pgprot_t protection_map[16] = {
    {__P000}, {__P001}, {__P010}, {__P011}, {__P100}, {__P101}, {__P110}, {__P111}, {__S000}, {__S001}, {__S010}, {__S011}, {__S100}, {__S101}, {__S110}, {__S111}};

int sysctl_max_map_count = 65505;

pgprot_t vm_get_page_prot(unsigned long vm_flags)
{
    return __pgprot((protection_map[vm_flags & (VM_READ | VM_WRITE | VM_EXEC | VM_SHARED)]));
}

struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
{
    struct vm_area_struct *vma = NULL;

    if (mm)
    {
        vma = mm->mmap_cache;

        if (!(vma && vma->vm_end > addr && vma->vm_start <= addr))
        {
            vma = mm->mmap;
            while (vma && vma->vm_end <= addr)
                vma = vma->vm_next;

            if (vma)
                mm->mmap_cache = vma;
        }
    }

    return vma;
}

struct vm_area_struct *find_vma_prev(struct mm_struct *mm, unsigned long addr, struct vm_area_struct **pprev)
{
    struct vm_area_struct *vma = NULL;
    struct vm_area_struct *prev = NULL;

    if (mm)
    {
        vma = mm->mmap;
        while (vma && vma->vm_end < addr)
        {
            prev = vma;
            vma = vma->vm_next;
        }

        *pprev = prev;
        return vma;
    }

    *pprev = NULL;
    return NULL;
}

struct vm_area_struct *find_vma_intersection(struct mm_struct *mm, unsigned long start_addr, unsigned long end_addr)
{
    struct vm_area_struct *vma = find_vma(mm, start_addr);

    if (vma && end_addr <= vma->vm_start)
        vma = NULL;
    return vma;
}

struct vm_area_struct *find_extend_vma(struct mm_struct *mm, unsigned long start_addr)
{
    return find_vma(mm, start_addr);
}

void __insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vmp)
{
    struct vm_area_struct **pprev;

    pprev = &mm->mmap;
    while (*pprev && (*pprev)->vm_start <= vmp->vm_start)
        pprev = &(*pprev)->vm_next;

    vmp->vm_next = *pprev;
    *pprev = vmp;

    mm->map_count++;
}

void lock_vma_mappings(struct vm_area_struct *vma)
{
}

void unlock_vma_mappings(struct vm_area_struct *vma)
{
}

void insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vmp)
{
     lock_vma_mappings(vmp);
     spin_lock(&current->mm->page_table_lock);
    __insert_vm_struct(mm, vmp);
     spin_unlock(&current->mm->page_table_lock);
     unlock_vma_mappings(vmp);
}

static inline void __remove_shared_vm_struct(struct vm_area_struct *vma)
{

}

static inline void remove_shared_vm_struct(struct vm_area_struct *vma)
{
    lock_vma_mappings(vma);
    __remove_shared_vm_struct(vma);
    unlock_vma_mappings(vma);
}


/*
 * 释放一个PMD条目对应的页表结构
 *
 * 以32位arm处理器为例，硬件mmu实际使用的是2级映射， pmd就等于pgd，一个pgd映射1M 大小的地址范围
 * 4GB地直空间全利用完就有4096个pgd, 一个小页(arm mmu中的小页)映射4k地址空间，那么一个pgd就对应256个小页，即256个pte项
 * 而free_one_pmd中只调用了一次pte_free是因为这256个pte表项全在这个页里，只需要释放这一个页面即可 
 */
static void free_one_pmd(pmd_t *dir)
{
    pte_t *pte;

    // 如果PMD条目为空，直接返回
    if (pmd_none(*dir))
        return;
    
     // 如果PMD条目损坏，报告错误并清除
    if (pmd_bad(*dir))
    {
        pmd_ERROR(*dir);
        pmd_clear(dir);
        return;
    }

    pte = pte_offset(dir, 0); // 获取PMD对应的PTE（Page Table Entry）表起始地址
    pmd_clear(dir); // 清除PMD条目
    pte_free(pte); // 释放PTE表占用的页面
}

/*
 * 释放一个PGD（Page Global Directory）条目对应的页表结构
 * 这会递归释放该PGD条目下的所有PMD和PTE
 */
static void free_one_pgd(pgd_t *dir)
{
    int j;
    pmd_t *pmd;

    // 如果PGD条目为空，直接返回
    if (pgd_none(*dir))
        return;

    // 如果PGD条目损坏，报告错误并清除
    if (pgd_bad(*dir))
    {
        pgd_ERROR(*dir);
        pgd_clear(dir);
        return;
    }

    pmd = pmd_offset(dir, 0); // 获取PGD对应的PMD表起始地址
    pgd_clear(dir);   // 清除PGD条目

    // 遍历PMD表中的所有条目
    for (j = 0; j < PTRS_PER_PMD; j++)
        free_one_pmd(pmd + j); // 递归释放每个PMD条目对应的页表
    
    // 释放PMD表占用的页面
    pmd_free(pmd);
}

/*
 * 清除指定范围内的页表结构
 * 从first开始的nr个PGD条目将被清理
 */
void clear_page_tables(struct mm_struct *mm, unsigned long first, int nr)
{
    pgd_t *page_dir = mm->pgd;

    // 定位到起始的PGD条目
    page_dir += first;
    do
    {
        // 释放单个PGD条目对应的所有下级页表
        free_one_pgd(page_dir);
        page_dir++;
    } while (--nr);
}

/*
 * 释放指定地址范围内的页表结构, 回收不再使用的页表页
 */
void free_pgtables(struct mm_struct *mm, struct vm_area_struct *prev, unsigned long start, unsigned long end)
{
    unsigned long first = start & PGDIR_MASK; // 计算起始地址对应的PGD目录索引（页全局目录）
    unsigned long last = end + PGDIR_SIZE - 1; // 计算结束地址对应的PGD目录索引，并扩展到整个PGD边界
    unsigned long start_index, end_index;
    struct vm_area_struct *next;

    // 如果prev为NULL，需要找到合适的起始VMA
    if (!prev)
    {
        // 从mm的第一个VMA开始
        prev = mm->mmap;
        if (!prev)
            goto no_mmaps; // 如果没有VMA，直接跳到清理阶段
        
        // 如果第一个VMA的结束地址大于start，需要调整边界
        if (prev->vm_end > start)
        {
            // 如果last超过了第一个VMA的起始地址，调整last
            if (last > prev->vm_start)
                last = prev->vm_start;

            goto no_mmaps; // 跳转到清理阶段
        }
    }

    // 遍历VMA链表，找到真正可以释放页表的边界
    for (;;)
    {
        next = prev->vm_next;

        if (next)
        {
            // 如果下一个VMA的起始地址小于start，继续向后查找
            if (next->vm_start < start)
            {
                prev = next;
                continue;
            }

            // 如果last超过了下一个VMA的起始地址，调整last
            if (last > next->vm_start)
                last = next->vm_start;
        }
        if (prev->vm_end > first)
            first = prev->vm_end + PGDIR_SIZE - 1;
        break;
    }
no_mmaps:
    /*
     * 如果虚拟地址中的PGD位不是连续的，
     * 传统的 VA >> PGDIR_SHIFT 方法就不适用了。
     * 这里使用pgd_index来计算索引
     */

    // 计算起始和结束的PGD索引
    start_index = pgd_index(first);
    end_index = pgd_index(last);

    // 只有在有多个PGD条目需要清理时才执行清理
    if (end_index > start_index)
    {
        // 清除指定范围内的页表
        clear_page_tables(mm, start_index, end_index - start_index);
        // 刷新TLB中的页表缓存
        flush_tlb_pgtables(mm, first & PGDIR_MASK, last & PGDIR_MASK);
    }
}

int vm_enough_memory(long pages)
{
    return 1;
}

/*
 * 修复解除映射后的VMA结构
 * 处理三种情况：完全解除映射、部分解除映射（头/尾）、中间挖洞
 */
static struct vm_area_struct *unmap_fixup(struct mm_struct *mm, struct vm_area_struct *area, unsigned long addr, unsigned long len, struct vm_area_struct *extra)
{
    struct vm_area_struct *mpnt;
    unsigned long end = addr + len; // 计算解除映射的结束地址

    // 更新内存统计信息：减少总虚拟内存页数
    area->vm_mm->total_vm -= len >> PAGE_SHIFT;
    // 如果区域被锁定，减少锁定内存页数
    if (area->vm_flags & VM_LOCKED)
        area->vm_mm->locked_vm -= len >> PAGE_SHIFT;

    // 情况1：完全解除整个VMA区域的映射
    if (addr == area->vm_start && end == area->vm_end)
    {
        // 如果有close操作，调用之
        if (area->vm_ops && area->vm_ops->close)
            area->vm_ops->close(area);
        
        if (area->vm_file)
            fput(area->vm_file); // 释放文件引用

        // 释放VMA结构本身
        kmem_cache_free(vm_area_cachep, area);
        return extra;  // 返回extra（未使用）
    }

     // 情况2：从尾部解除部分映射（调整结束地址
    if (end == area->vm_end)
    {
        area->vm_end = addr;  // 将VMA的结束地址调整为解除映射的起始地址
        lock_vma_mappings(area);  // 锁定VMA映射
        spin_lock(&mm->page_table_lock); // 获取页表锁
    }
    else if (addr == area->vm_start) // 情况3：从头部解除部分映射（调整起始地址
    {
        area->vm_pgoff += (end - area->vm_start) >> PAGE_SHIFT;  // 更新文件偏移（如果是文件映射）
        area->vm_start = end; // 将VMA的起始地址调整为解除映射的结束地址
        lock_vma_mappings(area);
        spin_lock(&mm->page_table_lock);
    }
    else
    {
        /*
         * 情况4：从中间解除映射（挖洞），需要拆分VMA
         * 解除中间区域的映射：area->vm_start < addr <= end < area->vm_end
         * 创建结束部分的映射 -- 开始部分留给下面的area
         */

        mpnt = extra; // 使用extra作为新的VMA来存储后半部分
        extra = NULL; // 标记extra已被使用

        // 初始化新VMA的各项属性
        mpnt->vm_mm = area->vm_mm;
        mpnt->vm_start = end; // 新VMA从解除映射结束处开始
        mpnt->vm_end = area->vm_end;  // 到原VMA结束处
        mpnt->vm_page_prot = area->vm_page_prot; 
        mpnt->vm_flags = area->vm_flags;
        mpnt->vm_raend = 0; 
        mpnt->vm_ops = area->vm_ops; // 继承操作函数集
        mpnt->vm_pgoff = area->vm_pgoff + ((end - area->vm_start) >> PAGE_SHIFT); // 计算新VMA的文件偏移
        mpnt->vm_private_data = area->vm_private_data;
        
        mpnt->vm_file = area->vm_file;
        if (mpnt->vm_file)
            get_file(mpnt->vm_file); //增加引用计数

        // 如果有open操作,则调用
        if (mpnt->vm_ops && mpnt->vm_ops->open)
            mpnt->vm_ops->open(mpnt); 
        
        // 调整原VMA的结束地址为解除映射的起始地址, 截断原区域
        area->vm_end = addr; 

        // 因为mpnt->vm_file == area->vm_file，锁操作能正确处理
        lock_vma_mappings(area);
        spin_lock(&mm->page_table_lock);

        __insert_vm_struct(mm, mpnt); // 将新VMA插入到内存结构中
    }

     // 重新插入调整后的原VMA（在情况2、3、4中都需要）
    __insert_vm_struct(mm, area);
    spin_unlock(&mm->page_table_lock); // 释放页表锁
    unlock_vma_mappings(area); // 解锁VMA映射

    return extra; // 返回extra（如果未被使用则原样返回，如果已使用则返回NULL）
}


/*
 * 2.x linux内核版本的 munmap函数
 */
int do_munmap(struct mm_struct *mm, unsigned long addr, unsigned int len)
{
    struct vm_area_struct *mpnt, *prev, **npp, *free, *extra;

    // if ((addr & ~PAGE_MASK) || addr > TASK_SIZE || len > TASK_SIZE - addr)
    // return -EINVAL;

    // 将长度按页对齐，如果对齐后为0则返回错误
    if ((len = PAGE_ALIGN(len)) == 0)
        return -EINVAL;

    // 查找包含addr的VMA及其前驱
    mpnt = find_vma_prev(mm, addr, &prev);
    if (!mpnt)
        return 0;

    // 如果找到的VMA起始地址 >= 要解除映射区域的结束地址，说明没有重叠
    if (mpnt->vm_start >= addr + len)
        return 0;

    // 如果VMA跨越了要解除映射的区域边界，且VMA数量已达上限，返回错误
    if ((mpnt->vm_start < addr && mpnt->vm_end > addr + len) && mm->map_count >= MAX_MAP_COUNT)
        return -ENOMEM;

    // 分配一个临时的VMA结构用于修复操作
    extra = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
    if (!extra)
        return -ENOMEM;

    // 确定遍历的起始指针
    npp = (prev ? &prev->vm_next : &mm->mmap);
    free = NULL;
    spin_lock(&mm->page_table_lock);
    // 遍历所有与解除映射区域重叠的VMA
    for (; mpnt && mpnt->vm_start < addr + len; mpnt = *npp)
    {
        *npp = mpnt->vm_next; // 从链表中移除当前VMA
        mpnt->vm_next = free; // 将当前VMA添加到free链表
        free = mpnt;
    }
    mm->mmap_cache = NULL;   // 清除mmap缓存
    spin_unlock(&mm->page_table_lock);

    // 遍历free链表，处理所有要解除映射的VMA
    while ((mpnt = free) != NULL)
    {
        unsigned long st, end, size;
        struct file *file = NULL;

        free = free->vm_next;

        // 计算实际要解除映射的起始和结束地址
        st = addr < mpnt->vm_start ? mpnt->vm_start : addr;
        end = addr + len;
        end = end > mpnt->vm_end ? mpnt->vm_end : end;
        size = end - st;
        
        // 修改文件映射的写计数
        if (mpnt->vm_flags & VM_DENYWRITE &&
            (st != mpnt->vm_start || end != mpnt->vm_end) &&
            (file = mpnt->vm_file) != NULL)
        {
            //atomic_dec(&file->f_dentry->d_inode->i_writecount);
        }
        
        // 从共享vm结构中移除
        remove_shared_vm_struct(mpnt);
        mm->map_count--;

        // flush_cache_range(mm, st, end); //缓存刷新和TLB刷新
        zap_page_range(mm, st, size); // 清除页表项
        // flush_tlb_range(mm, st, end);

        extra = unmap_fixup(mm, mpnt, st, size, extra); // 修复VMA结构（拆分或调整）

        if (file)
        {
            //atomic_inc(&file->f_dentry->d_inode->i_writecount);
        }
    }

     // 释放临时VMA结构
    if (extra)
        kmem_cache_free(vm_area_cachep, extra);

    // 释放页表
    free_pgtables(mm, prev, addr, addr + len);

    return 0;
}

long sys_munmap(unsigned long addr, unsigned int len)
{
    int ret;
    struct mm_struct *mm = current->mm;

    // down(&mm->mmap_sem);
    ret = do_munmap(mm, addr, len);
    // up(&mm->mmap_sem);
    return ret;
}

void unmap_region(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *prev, unsigned long start, unsigned long end)
{
}

void __vma_link_rb(struct mm_struct *mm, struct vm_area_struct *vma, struct rb_node **rb_link, struct rb_node *rb_parent)
{
}

void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *prev, struct rb_node *rb_parent)
{
    struct vm_area_struct *next;

    vma->vm_prev = prev;
    if (prev)
    {
        next = prev->vm_next;
        prev->vm_next = vma;
    }
    else
    {
        mm->mmap = vma;
        if (rb_parent)
            next = rb_entry(rb_parent, struct vm_area_struct, vm_rb);
        else
            next = NULL;
    }
    vma->vm_next = next;
    if (next)
        next->vm_prev = vma;
}

static void __vma_link_file(struct vm_area_struct *vma)
{
}

static void __vma_link(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *prev, struct rb_node **rb_link, struct rb_node *rb_parent)
{
    __vma_link_list(mm, vma, prev, rb_parent);
    __vma_link_rb(mm, vma, rb_link, rb_parent);
}

static void vma_link(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *prev, struct rb_node **rb_link, struct rb_node *rb_parent)
{
    struct address_space *mapping = NULL;

    if (vma->vm_file)
    {
        mapping = vma->vm_file->f_mapping;
        // i_mmap_lock_write(mapping);
    }

    __vma_link(mm, vma, prev, rb_link, rb_parent);
    __vma_link_file(vma);

    if (mapping)
    {
        // i_mmap_unlock_write(mapping);
    }

    mm->map_count++;
}

unsigned long vm_unmapped_area(unsigned long addr, unsigned long len)
{
    struct vm_area_struct *vma;
    if (!addr)
    {
    }
    addr = PAGE_ALIGN(addr);

    // 循环查找当前addr是否与任何VMA重叠
    for (vma = find_vma(current->mm, addr);; vma = vma->vm_next)
    {
        if (TASK_SIZE - len < addr)
            return 0;

        // 如果没有找到VMA或当前地址加长度在VMA起始地址之前，说明该区域未被映射
        if (!vma || addr + len <= vma->vm_start)
            return addr;

        // 否则，将地址移动到当前VMA的结束位置，继续查找
        addr = vma->vm_end;
    }
}

unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
{
    if (len > TASK_SIZE)
        return -ENOMEM;

    return vm_unmapped_area(addr, len);
}

/*
 * 获取一段未映射区域
 */
unsigned long get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
{
    unsigned long (*get_area)(struct file *, unsigned long,
                              unsigned long, unsigned long, unsigned long);

    // get_area = current->mm->get_unmapped_area;
    get_area = arch_get_unmapped_area;
    if (file)
    {
        if (file->f_op->get_unmapped_area)
            get_area = file->f_op->get_unmapped_area;
    }
    else if (flags & MAP_SHARED)
    {
        // pgoff = 0;
        // get_area = shmem_get_unmapped_area;
    }

    addr = get_area(file, addr, len, pgoff, flags);
    if (IS_ERR_VALUE(addr))
        return addr;

    if (addr > TASK_SIZE - len)
        return -ENOMEM;

    if (offset_in_page(addr))
        return -EINVAL;

    return addr;
}

void vma_set_page_prot(struct vm_area_struct *vma)
{
}

int may_expand_vm(struct mm_struct *mm, unsigned long flags, unsigned long npages)
{
    return 1;
}

int find_vma_links(struct mm_struct *mm, unsigned long addr, unsigned long end, struct vm_area_struct **pprev, struct rb_node ***rb_link, struct rb_node **rb_parent)
{
    return find_vma_prev(mm, addr, pprev) ? 1 : 0;
}

/*
 * VMA合并
 * 减少VMA数量，简化内存管理, 对相邻的VMA且有相同的属性（权限、文件、偏移等）进行合并
 *
 * 例：两个相邻的共享匿名映射可能被合并
 * VMA1: 0x1000-0x2000, shared, anonymous, pgoff=0
 * VMA2: 0x2000-0x3000, shared, anonymous, pgoff=0
 * 合并后:
 * VMA: 0x1000-0x3000, shared, anonymous, pgoff=0
 */
struct vm_area_struct *vma_merge(struct mm_struct *mm, struct vm_area_struct *prev, unsigned long addr, unsigned long end,
                                 unsigned long vm_flags, void *anon_vma, struct file *file,
                                 unsigned long pgoff, void *policy)
{
    return NULL;
}

/*
 * mmap核心函数
 */
unsigned long mmap_region(struct file *file, unsigned long addr, unsigned long len, unsigned long vm_flags, unsigned long pgoff)
{
    struct mm_struct *mm = current->mm;
    struct vm_area_struct *vma, *prev;
    int error;
    // unsigned long charged = 0;
    struct rb_node **rb_link, *rb_parent;

    // 检查是否可以扩展虚拟内存空间
    if (!may_expand_vm(mm, vm_flags, len >> PAGE_SHIFT))
    {
        // 如果不能扩展，应该返回-ENOMEM错误
        return -ENOMEM;
    }

    // 循环查找并处理地址冲突：如果指定地址已被映射，则取消现有映射
    while (find_vma_links(mm, addr, addr + len, &prev, &rb_link, &rb_parent))
    {
        if (do_munmap(mm, addr, len))
            return -ENOMEM;
    }

    // 尝试合并相邻的VMA区域：检查是否可以与相邻VMA合并
    vma = vma_merge(mm, prev, addr, addr + len, vm_flags, NULL, file, pgoff, NULL);
    if (vma)
        goto out;

    // 分配新的VMA结构体
    vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);
    if (!vma)
        return -ENOMEM; // 内存分配失败

    // 初始化VMA结构体字段
    vma->vm_mm = mm;
    vma->vm_start = addr;
    vma->vm_end = addr + len;
    vma->vm_flags = vm_flags;
    vma->vm_page_prot = vm_get_page_prot(vm_flags);
    INIT_LIST_HEAD(&vma->list);

    // 文件映射处理
    if (file)
    {
        // 如果设置了VM_DENYWRITE标志，拒绝文件的写访问
        if (vm_flags & VM_DENYWRITE)
        {
            error = deny_write_access(file);
            if (error)
                goto free_vma; // 失败则跳转到清理
        }

        // 如果是共享映射，确保文件映射可写
        if (vm_flags & VM_SHARED)
        {
            error = mapping_map_writable(file->f_mapping);
            if (error)
                goto allow_write_and_free_vma;
        }

        // 关联文件并增加文件引用计数
        vma->vm_file = get_file(file);
        error = file->f_op->mmap(file, vma); // 调用文件系统的mmap操作
        if (error)
            goto unmap_and_free_vma;

        // 更新地址和标志（文件系统的mmap可能修改了这些值）
        addr = vma->vm_start;
        vm_flags = vma->vm_flags;
    }
    else if (vm_flags & VM_SHARED) // 匿名共享映射处理
    {
        // error = shmem_zero_setup(vma);
    }

    // 将VMA插入进程的红黑树和链表中
    vma_link(mm, vma, prev, rb_link, rb_parent);

    // 文件映射的后续处理
    if (file)
    {
        // 如果是共享映射，取消映射的可写标记
        if (vm_flags & VM_SHARED)
            mapping_unmap_writable(file->f_mapping);

        // 如果之前拒绝了写访问，现在重新允许
        if (vm_flags & VM_DENYWRITE)
            allow_write_access(file);
    }
    file = vma->vm_file;
out:
    vma->vm_flags |= VM_SOFTDIRTY; // 标记为已修改
    vma_set_page_prot(vma);        // 设置页面保护权限

    return addr;

unmap_and_free_vma:
    vma->vm_file = NULL;                                     // 清除文件关联
    fput(file);                                              // 释放文件引用
    unmap_region(mm, vma, prev, vma->vm_start, vma->vm_end); // 取消映射区域
    if (vm_flags & VM_SHARED)
    {
        // 共享映射的额外清理操作
        // mapping_unmap_writable(file->f_mapping);
    }
allow_write_and_free_vma:
    if (vm_flags & VM_DENYWRITE)
    {
        // 重新允许文件写访问
        allow_write_access(file);
    }
free_vma:
    kmem_cache_free(vm_area_cachep, vma);
    return error;
}

unsigned long do_mmap(struct file *file, unsigned long addr,
                      unsigned long len, unsigned long prot,
                      unsigned long flags, unsigned long vm_flags,
                      unsigned long pgoff, unsigned long *populate)
{
    struct mm_struct *mm = current->mm;

    // 默认不进行页面预分配
    *populate = 0;

    // 判断长度是否合法
    if (!len)
        return -EINVAL;

    // 对齐长度
    len = PAGE_ALIGN(len);
    if (!len)
        return -ENOMEM;

    // 检查偏移量是否溢出
    if (pgoff + (len >> PAGE_SHIFT) < pgoff)
        return -EOVERFLOW;

    // 检查进程的内存映射数量是否超过限制
    if (mm->map_count > sysctl_max_map_count)
    {
    }

    // 获取未映射区域的起始地址
    addr = get_unmapped_area(file, addr, len, pgoff, flags);
    if (offset_in_page(addr)) // 4096对齐检查
        return addr;

    if (prot == PROT_EXEC)
    {
    }

    // 根据文件和映射类型设置vm_flags
    if (file)
    {
        // struct inode *inode = file->f_inode;
        switch (flags & MAP_TYPE)
        {
        case MAP_SHARED:                                              // 共享映射
            if ((prot & PROT_WRITE) && !(file->f_mode & FMODE_WRITE)) // 写权限检查
                return -EACCES;

            vm_flags |= VM_SHARED | VM_MAYSHARE;        // 设置共享标志
            if (!(file->f_mode & FMODE_WRITE))          // 只读文件处理
                vm_flags &= ~(VM_MAYWRITE | VM_SHARED); // 移除写权限标志

            break;
        case MAP_PRIVATE:                     // 私有映射
            if (!(file->f_mode & FMODE_READ)) // 读权限检查
                return -EACCES;
            // if (path_noexec(&file->f_path))
            //{
            // if (vm_flags & VM_EXEC)
            // return -EACCES;
            // vm_flags &= ~VM_MAYEXEC;
            //}
            if (!file->f_op->mmap) // mmap操作检查
                return -ENODEV;

            if (vm_flags & (VM_GROWSDOWN | VM_GROWSUP)) // 检查是否为堆栈映射
                return -EINVAL;
            break;
        default:
            return -EINVAL;
        }
    }
    else // 匿名映射
    {
        switch (flags & MAP_TYPE)
        {
        case MAP_SHARED:
            if (vm_flags & (VM_GROWSDOWN | VM_GROWSUP)) // 检查是否为堆栈映射
                return -EINVAL;
            pgoff = 0;                           // 匿名映射偏移量为0，多个相邻匿名共享映射都有pgoff=0方便内核合并，
            vm_flags |= VM_SHARED | VM_MAYSHARE; // 设置共享标志
            break;
        case MAP_PRIVATE:               // 私有映射
            pgoff = addr >> PAGE_SHIFT; // 设置偏移量为地址页号,确保每个私有映射都有唯一的pgoff，防止VMA合并. 私有映射可能会使用写时复制,合并会破坏写时复制的正确性
            break;
        default:
            return -EINVAL;
        }
    }

    // 调用mmap_region进行实际的内存映射
    addr = mmap_region(file, addr, len, vm_flags, pgoff);

    // 如果映射成功且需要锁定页面或者包括MAP_POPULATE标志，则设置预分配长度
    if (!IS_ERR_VALUE(addr) && (flags & VM_LOCKED)) //  || (flags & (MAP_POPULATE) == MMAP_POPULATE))
        *populate = len;

    return addr;
}

unsigned long vm_mmap_pgoff(struct file *file, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long pgoff)
{
    unsigned long ret;
    unsigned long populate;

    // down_write_killable(&mm->mmap_sem);

    ret = do_mmap(file, addr, len, prot, flags, flags, pgoff, &populate);
    if (populate)
    {
    }
    // up_write(&mm->mmap_sem);

    // 如果需要populate，则进行预分配页面
    if (populate)
        mm_populate(ret, populate);

    return ret;
}

/*
 * 4.x版本linux内核，系统调用mmap入口
 */
unsigned long sys_mmap_pgoff(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff)
{
    struct file *file = NULL;
    unsigned long retval = 0;

    if (!(flags & MAP_ANONYMOUS))
    {
        file = fget(fd);
        if (!file)
        {
        }
    }

    flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);

    retval = vm_mmap_pgoff(file, addr, len, prot, flags, pgoff);

    if (file)
        fput(file);

    return retval;
}

unsigned long do_brk(unsigned long addr, unsigned long len)
{
    struct mm_struct *mm = current->mm;
    struct vm_area_struct *vma;
    unsigned long flags, retval;

    // 将长度按页大小对齐
    len = PAGE_ALIGN(len);
    // 如果对齐后长度为0，直接返回地址
    if (!len)
        return addr;

    // 先解除addr开始长度为len区域的现有映射
    retval = do_munmap(mm, addr, len);
    if (retval != 0)
        return retval;

#if 0
    // 地址空间限制检查
    if ((mm->total_vm << PAGE_SHIFT) + len > current->rlim[RLIMIT_AS].rlim_cur)
        return -ENOMEM;
#endif

    // 检查虚拟内存区域数量是否超过限制
    if (mm->map_count > MAX_MAP_COUNT)
        return -ENOMEM;

    // 检查是否有足够的物理内存
    if (!vm_enough_memory(len >> PAGE_SHIFT))
        return -ENOMEM;

    // 设置虚拟内存区域的标志位
    flags = VM_DATA_DEFAULT_FLAGS | mm->def_flags;

    // 添加允许读、写、执行和锁定标志
    flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC | VM_LOCKED;

    // 检查是否可以扩展现有的匿名映射区域
    if (addr)
    {
        vma = find_vma(mm, addr - 1);
        if (vma && vma->vm_end == addr && !vma->vm_file && vma->vm_flags == flags)
        {
            vma->vm_end = addr + len;
            goto out;
        }
    }

    // 分配新的vm_area_struct结构
    vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
    if (!vma)
        return -ENOMEM;

    // 初始化VMA的各个字段
    vma->vm_mm = mm;
    vma->vm_start = addr;
    vma->vm_end = addr + len;
    vma->vm_flags = flags;
    vma->vm_page_prot = protection_map[flags & 0x0f];
    vma->vm_ops = NULL;
    vma->vm_pgoff = 0;
    vma->vm_file = NULL;
    vma->vm_private_data = NULL;

    // 将新的VMA插入到进程的虚拟内存区域列表中
    insert_vm_struct(mm, vma);

out:
    mm->total_vm += len >> PAGE_SHIFT; // 更新总虚拟内存页数
    mm->data_vm += len >> PAGE_SHIFT; // 更新数据段虚拟内存页数
    if (flags & VM_LOCKED) // 如果区域被锁定，需要立即分配物理页面
    {
        mm->locked_vm += len >> PAGE_SHIFT; // 更新锁定内存页数
        make_pages_present(addr, addr + len); // 立即分配物理页面(4.x代码使用mm_populate函数)
    }
    return addr;
}

/*
 * 2.x版本linux内核，系统调用brk入口
 */
unsigned long sys_brk(unsigned long brk)
{
    // unsigned long rlim; // 用于资源限制检查
    unsigned long retval;
    unsigned long newbrk, oldbrk; // 新的和旧的brk边界（页对齐后）
    struct mm_struct *mm;

    // 获取当前进程的内存管理结构
    mm = current->mm; 

    // down(&mm->mmap_sem);

    // 新的brk不能低于代码段结束地址
    if (brk < mm->end_code)
        goto out;

    newbrk = PAGE_ALIGN(brk);  // 将请求的brk地址按页大小对齐
    oldbrk = PAGE_ALIGN(mm->brk); // 将当前brk地址按页大小对齐
    if (oldbrk == newbrk) // 如果新旧brk相同（在页对齐后），直接设置brk值
        goto set_brk;

    // 缩小空间
    if (brk <= mm->brk)
    {
        // 解除从newbrk到oldbrk区间的内存映射
        if (!do_munmap(mm, newbrk, oldbrk - newbrk))
            goto set_brk; // 如果解除映射成功，设置新的brk值
        goto out; // 如果失败，保持原brk值
    }
#if 0
    // 资源限制检查 
    rlim = current->rlim[RLIMIT_DATA].rlim_cur;
    if (rlim < RLIM_INFINITY && brk - mm->start_data > rlim)
        goto out;
#endif

    // 检查新brk区间是否与现有内存映射区域冲突
    if (find_vma_intersection(mm, oldbrk, newbrk + PAGE_SIZE))
        goto out;

    // 检查是否有足够的内存满足请求
    if (!vm_enough_memory((newbrk - oldbrk) >> PAGE_SHIFT))
        goto out;

    // 执行实际的扩展操作
    if (do_brk(oldbrk, newbrk - oldbrk) != oldbrk)
        goto out;

set_brk:
    mm->brk = brk; // 设置新的brk值（注意：这里使用原始brk值，不是页对齐后的值）
out:
    retval = mm->brk; // 返回当前的brk值（可能是新的，也可能是原来的）
    //	up(&mm->mmap_sem);
    return retval;
}

/*
 * 释放所有的内存映射区域和页表
 */
void exit_mmap(struct mm_struct *mm)
{
    struct vm_area_struct *mpnt;

    spin_lock(&mm->page_table_lock);
    mpnt = mm->mmap;
    spin_unlock(&mm->page_table_lock);
    mm->rss = 0;
    mm->total_vm = 0;
    mm->locked_vm = 0;
    while (mpnt)
    {
        struct vm_area_struct *next = mpnt->vm_next;
        unsigned long start = mpnt->vm_start;
        unsigned long end = mpnt->vm_end;
        unsigned long size = end - start;

        if (mpnt->vm_ops)
        {
            if (mpnt->vm_ops->close)
                mpnt->vm_ops->close(mpnt);
        }
        mm->map_count--;
        remove_shared_vm_struct(mpnt); // 删除共享VMA结构
        // flush_cache_range(mm, start, end); //TODO fix me here
        zap_page_range(mm, start, size); // 取消start-size范围内的映射

        if (mpnt->vm_file)
            fput(mpnt->vm_file);

        kmem_cache_free(vm_area_cachep, mpnt); // 释放VMA结构体
        mpnt = next;
    }

    // 调试
    if (mm->map_count)
        printk("exit_mmap: map count is %d\n", mm->map_count);

    // 释放页表
    clear_page_tables(mm, FIRST_USER_PGD_NR, USER_PTRS_PER_PGD);
}

void show_pte(pte_t *pte)
{
    int i;
    // unsigned long *p;

    if (!pte)
        return;

    // p = (unsigned long *)pte->pte;
    for (i = 0; i < 1024; i++)
    {
        if (pte_val(*pte))
        {
            printk("i: %d pte: %p pte->pte: %lx\n", i, pte, pte->pte);
        }
        pte++;
    }
}

void show_pmd(pmd_t *pmd)
{
    int i;
    pte_t *pte;

    pte = (pte_t *)pmd_page(*pmd) + 0;

    for (i = 0; i < 1024; i++)
    {
        if (pte && pte_val(*pte))
        {
            printk("pte%d: %p pte->pte: %lx\n", i, pte, pte->pte);
        }
        pte++;
    }
}

void show_pgd(pgd_t *pgd)
{
    int i;
    pmd_t *pmd;

    pmd = pmd_alloc(pgd, 0);

    for (i = 0; i < 1024; i++)
    {
        if (pmd_val(*pmd))
        {
            printk("pmd%d: %p pmd->pmd: %lx\n", i, pmd, pmd->pmd);
            show_pmd(pmd);
        }
        pmd++;
    }
}

void show_mm(struct mm_struct *mm)
{
    struct vm_area_struct *vma = NULL;

    if (mm && mm->mmap)
    {
        vma = mm->mmap;

        printk("\nmm: %p\n", mm);
        printk("mm->mmap: %p\n", mm->mmap);
        printk("mm->def_flags: %lx\n", mm->def_flags);
        printk("mm->pgd: %p\n", mm->pgd);
        show_pgd(mm->pgd);

        while (vma)
        {
            printk("vma->start: %lx\n", vma->vm_start);
            printk("vma->end: %lx\n", vma->vm_end);
            vma = vma->vm_next;
        }
    }
}
